"""
扫货账号池管理类
"""
import random
import time
import threading
import json
from typing import Optional, Dict, Any, List
from datetime import datetime
from com.db.scan_account_manager import ScanAccountManager
from com.db.cons_manager import ConsManager
from com.utils.logger import get_logger, MODULE_ACCOUNT_POOL

class ScanAccountPool:
    def __init__(self):
        """初始化扫货账号池"""
        self.account_manager = ScanAccountManager()
        self.cons_manager = ConsManager()
        # 存储账号及其下次可用时间
        self.account_pool = {}  # {account_id: {'account': account_info, 'next_available_time': timestamp}}
        # 频率配置
        self.frequency_configs = []
        # 获取logger
        self.logger = get_logger(MODULE_ACCOUNT_POOL)
        # self.logger.info("初始化扫货账号池")
        # 加载频率配置
        self._load_frequency_configs()
        # 加载账号
        self._load_accounts()
        # 定时任务定时器
        self.status_check_timer = None
        # 启动定时检查
        self._start_status_check()
    
    def _load_accounts(self):
        """从数据库加载扫货账号"""
        try:
            # 使用ScanAccountManager获取活跃账号
            accounts = self.account_manager.get_active_accounts()
            
            current_time = time.time()
            for account in accounts:
                self.account_pool[str(account['id'])] = {  # 确保id是字符串类型
                    'account': account,
                    'next_available_time': current_time
                }
            # self.logger.info(f"已加载 {len(accounts)} 个扫货账号到账号池")
        except Exception as e:
            self.logger.error(f"加载扫货账号时发生错误: {str(e)}")
    
    def _generate_random_interval(self, min_interval: int) -> float:
        """
        生成随机间隔时间，80%的概率在30%-100%范围内
        
        Args:
            min_interval: 最小间隔时间（秒）
            
        Returns:
            随机生成的间隔时间（秒）
        """
        if random.random() < 0.8:  # 80%的概率
            # 在30%-100%范围内生成
            return random.uniform(min_interval * 0.3, min_interval)
        else:  # 20%的概率
            # 在0-30%范围内生成
            return random.uniform(0, min_interval * 0.3)
    
    def get_accounts_with_intervals(self, count: int) -> List[Dict[str, Any]]:
        """
        获取指定数量的账号和执行时间列表，如果请求数量大于账号总数，会重复使用账号
        
        Args:
            count: 需要的账号数量
            
        Returns:
            账号列表，每个元素包含:
            - account: 账号信息
            - interval: 随机生成的执行间隔时间（秒）
            - next_available_time: 下次可用时间戳
        """
        if not self.account_pool:
            self.logger.warning("账号池为空，尝试重新加载账号")
            return []
        
        result = []
        remaining_count = count
        
        while remaining_count > 0:
            current_time = time.time()
            
            # 获取所有账号及其下次可用时间
            accounts_with_time = [
                (account_id, info, info.get('next_available_time', current_time))
                for account_id, info in self.account_pool.items()
            ]
            
            # 按照next_available_time排序
            accounts_with_time.sort(key=lambda x: x[2])
            
            # 本轮需要获取的账号数量
            current_round_count = min(remaining_count, len(accounts_with_time))
            
            # 获取next_available_time最早的current_round_count个账号
            selected_accounts = accounts_with_time[:current_round_count]
            
            for account_id, info, next_time in selected_accounts:
                # 生成随机间隔时间
                min_interval = info['account']['min_interval']
                interval = self._generate_random_interval(min_interval)
                
                # 获取当前时间段的频率百分比并调整间隔
                frequency = self._get_current_frequency()
                # 添加安全检查，确保频率不为0
                if frequency <= 0:
                    # self.logger.warning(f"账号 {account_id} 的频率配置异常（{frequency}），使用默认值 1.0")
                    frequency = 1.0
                adjusted_interval = interval * frequency  # 直接乘以频率百分比
                
                # 更新账号的下次可用时间
                new_next_available_time = max(current_time, next_time) + adjusted_interval
                self.account_pool[account_id]['next_available_time'] = new_next_available_time
                
                # 记录调整日志
                # if frequency != 1.0:
                #     self.logger.debug(f"账号 {account_id} 的间隔时间从 {interval:.2f} 秒调整为 {adjusted_interval:.2f} 秒（频率配置 {frequency*100:.0f}%）")
                
                # 在返回结果中直接使用调整后的间隔时间作为interval字段
                # 这样调用方不需要修改代码就能使用正确的间隔时间
                result.append({
                    'account': info['account'],
                    'interval': round(adjusted_interval, 2),  # 使用调整后的间隔时间
                    'original_interval': round(interval, 2),  # 保留原始间隔时间供参考
                    'next_available_time': new_next_available_time
                })
            
            remaining_count -= current_round_count
            
        # self.logger.debug(f"获取 {count} 个账号，实际返回 {len(result)} 个")
        return result

    def get_accounts_by_ids(self, account_ids: List[int]) -> List[Dict[str, Any]]:
        """
        根据账号ID列表获取账号信息及其下次可用时间
        
        Args:
            account_ids: 账号ID列表
            
        Returns:
            账号列表，每个元素包含:
            - account: 账号信息
            - interval: 随机生成的执行间隔时间（秒）
            - next_available_time: 下次可用时间戳
        """
        if not self.account_pool:
            self.logger.warning("账号池为空，尝试重新加载账号")
            self._load_accounts()
            
        current_time = time.time()
        result = []
        
        # 获取所有指定账号及其下次可用时间
        accounts_with_time = []
        
        # 区分池中已有的账号和需要从数据库获取的账号
        missing_account_ids = []
        for account_id in account_ids:
            account_info = self.account_pool.get(str(account_id))
            if account_info:
                accounts_with_time.append((
                    str(account_id),
                    account_info,
                    account_info.get('next_available_time', current_time)
                ))
            else:
                missing_account_ids.append(account_id)
        
        # 批量获取缺失的账号信息
        if missing_account_ids:
            # self.logger.info(f"从数据库获取 {len(missing_account_ids)} 个缺失账号")
            accounts = self.account_manager.get_accounts_by_ids(missing_account_ids)
            for account in accounts:
                account_id = str(account['id'])
                account_info = {
                    'account': account,
                    'next_available_time': current_time
                }
                self.account_pool[account_id] = account_info
                accounts_with_time.append((
                    account_id,
                    account_info,
                    current_time
                ))
        
        # 按照next_available_time排序
        accounts_with_time.sort(key=lambda x: x[2])
        
        # 处理每个账号
        for account_id, info, next_time in accounts_with_time:
            # 生成随机间隔时间
            min_interval = info['account'].get('usage_frequency', 60)  # 使用usage_frequency字段，默认60秒
            interval = self._generate_random_interval(min_interval)
            
            # 获取当前时间段的频率百分比并调整间隔
            frequency = self._get_current_frequency()
            # 添加安全检查，确保频率不为0
            if frequency <= 0:
                # self.logger.warning(f"账号 {account_id} 的频率配置异常（{frequency}），使用默认值 1.0")
                frequency = 1.0
            adjusted_interval = interval * frequency  # 直接乘以频率百分比
            
            # 更新账号的下次可用时间
            new_next_available_time = max(current_time, next_time) + adjusted_interval
            
            # 记录调整日志
            # if frequency != 1.0:
                # self.logger.debug(f"账号 {account_id} 的间隔时间从 {interval:.2f} 秒调整为 {adjusted_interval:.2f} 秒（频率配置 {frequency*100:.0f}%）")
            self.account_pool[account_id]['next_available_time'] = new_next_available_time
            
            # 在返回结果中直接使用调整后的间隔时间作为interval字段
            result.append({
                'account': info['account'],
                'interval': round(adjusted_interval, 2),  # 使用调整后的间隔时间
                'original_interval': round(interval, 2),  # 保留原始间隔时间供参考
                'next_available_time': new_next_available_time,
                'next_available_time_str': datetime.fromtimestamp(new_next_available_time).strftime('%Y-%m-%d %H:%M:%S')
            })
        
        # self.logger.debug(f"根据ID获取账号，请求 {len(account_ids)} 个，实际返回 {len(result)} 个")
        return result

    def refresh_accounts(self):
        """刷新账号池中的账号"""
        # self.logger.info("开始刷新账号池")
        self.account_pool.clear()
        # 重新加载频率配置
        self._load_frequency_configs()
        # 重新加载账号
        self._load_accounts()

    def _load_frequency_configs(self):
        """从数据库加载频率配置"""
        try:
            # 从数据库加载配置
            config_json = self.cons_manager.get_value("SCAN_FREQUENCY_CONFIG")
            
            if config_json:
                # 将JSON字符串转换为配置列表
                self.frequency_configs = json.loads(config_json)
                # self.logger.info(f"已加载 {len(self.frequency_configs)} 个扫货频率配置")
                # for config in self.frequency_configs:
                #     self.logger.debug(f"频率配置: 时间段={config['time_range']}, 频率={config['frequency']}")
            else:
                # 如果没有配置，初始化空列表
                self.frequency_configs = []
                # self.logger.warning("未找到扫货频率配置，使用默认配置")
        except Exception as e:
            # self.logger.error(f"加载扫货频率配置时出错: {str(e)}")
            self.frequency_configs = []
    
    def _get_current_frequency(self):
        """获取当前时间段的频率百分比
        
        Returns:
            float: 当前时间段的频率百分比，如果没有匹配的时间段则返回1.0（100%）
        """
        if not self.frequency_configs:
            return 1.0  # 如果没有配置，返回100%
        
        # 获取当前时间
        current_time = datetime.now().time()
        current_minutes = current_time.hour * 60 + current_time.minute
        
        # 遍历所有配置，检查当前时间是否在时间段内
        for config in self.frequency_configs:
            time_range = config["time_range"]
            frequency_str = config["frequency"]
            
            # 解析时间范围
            start_time_str, end_time_str = time_range.split("-")
            start_hour, start_minute = map(int, start_time_str.split(":"))
            end_hour, end_minute = map(int, end_time_str.split(":"))
            
            start_minutes = start_hour * 60 + start_minute
            end_minutes = end_hour * 60 + end_minute
            
            # 检查是否跨午夜
            crosses_midnight = end_minutes < start_minutes
            
            # 判断当前时间是否在时间段内
            in_range = False
            if crosses_midnight:
                # 如果跨午夜，则判断当前时间是否在开始时间之后或结束时间之前
                if current_minutes >= start_minutes or current_minutes < end_minutes:
                    in_range = True
            else:
                # 如果不跨午夜，则判断当前时间是否在开始时间和结束时间之间
                if start_minutes <= current_minutes < end_minutes:
                    in_range = True
            
            if in_range:
                # 解析频率百分比
                frequency = float(frequency_str.strip("%")) / 100.0
                # self.logger.debug(f"当前时间 {current_time.strftime('%H:%M')} 在时间段 {time_range} 内，频率为 {frequency_str}")
                return frequency
        
        # 如果没有匹配的时间段，返回100%
        # self.logger.debug(f"当前时间 {current_time.strftime('%H:%M')} 没有匹配的频率配置，使用默认频率 100%")
        return 1.0
    
    def _sync_account_pool_status(self):
        """
        同步账号池状态
        1. 检查现有账号的状态，移除不可用账号
        2. 添加新增的活跃账号
        3. 恢复之前被移除但现在已恢复的账号
        4. 更新频率配置
        """
        try:
            # self.logger.debug("开始同步账号池状态")
            
            # 更新频率配置
            self._load_frequency_configs()
            
            # 获取所有活跃账号
            current_accounts = self.account_manager.get_active_accounts()
            current_time = time.time()
            
            # 将当前活跃账号转换为字典，方便查找
            current_accounts_dict = {str(acc['id']): acc for acc in current_accounts}
            
            # 1. 检查现有账号并移除不可用账号
            accounts_to_remove = []
            for account_id in list(self.account_pool.keys()):
                account = current_accounts_dict.get(account_id)
                if not account or not account.get('alive') or account.get('status') != 1:
                    accounts_to_remove.append(account_id)
            
            # 从池中移除不可用的账号
            for account_id in accounts_to_remove:
                account_info = self.account_pool.pop(account_id, None)
                if account_info:
                    self.logger.warning(f"账号 {account_id} 状态异常，已从账号池中移除")
            
            # 2. 添加新增的活跃账号
            new_accounts = []
            for account_id, account in current_accounts_dict.items():
                if account_id not in self.account_pool:
                    new_accounts.append(account)
                    self.account_pool[account_id] = {
                        'account': account,
                        'next_available_time': current_time
                    }
            
            if new_accounts:
                # self.logger.info(f"发现 {len(new_accounts)} 个新增或恢复的账号:")
                for account in new_accounts:
                    self.logger.info(f"账号ID: {account['id']}, 名称: {account.get('name', 'unknown')}")
            
            # 3. 更新现有账号的信息
            updated_accounts = []
            for account_id, account in current_accounts_dict.items():
                if account_id in self.account_pool:
                    old_account = self.account_pool[account_id]['account']
                    # 检查账号信息是否有更新 - 不再仅检查特定字段，而是比较所有字段
                    has_changes = False
                    for key, value in account.items():
                        if old_account.get(key) != value:
                            has_changes = True
                            break
                    
                    if has_changes:
                        updated_accounts.append(account)
                        # 保持原有的next_available_time
                        next_time = self.account_pool[account_id]['next_available_time']
                        self.account_pool[account_id] = {
                            'account': account,
                            'next_available_time': next_time
                        }
            
            # if updated_accounts:
            #     self.logger.info(f"更新 {len(updated_accounts)} 个账号的信息:")
            #     for account in updated_accounts:
            #         self.logger.debug(f"账号ID: {account['id']}, 名称: {account.get('name', 'unknown')} 信息已更新")
            
            # self.logger.debug(f"账号池同步完成，当前共有 {len(self.account_pool)} 个可用账号，{len(self.frequency_configs)} 个频率配置")
                
        except Exception as e:
            self.logger.error(f"同步账号池状态时发生错误: {str(e)}")
        finally:
            # 重新设置定时器
            self._start_status_check()

    def _start_status_check(self):
        """启动定时同步任务"""
        if self.status_check_timer:
            self.status_check_timer.cancel()
        self.status_check_timer = threading.Timer(30, self._sync_account_pool_status)
        self.status_check_timer.daemon = True
        self.status_check_timer.start()
        # self.logger.debug("启动定时同步任务")

    def stop_status_check(self):
        """停止定时同步任务"""
        if self.status_check_timer:
            self.status_check_timer.cancel()
            self.status_check_timer = None
            # self.logger.info("停止定时同步任务")

def main():
    """测试扫货账号池功能"""
    import json
    from unittest.mock import patch
    from datetime import datetime, time as dt_time
    
    # 创建账号池实例，会自动从数据库加载频率配置
    pool = ScanAccountPool()
    
    # 打印当前频率配置
    print("\n当前频率配置:")
    for i, config in enumerate(pool.frequency_configs, 1):
        print(f"  {i}. 时间段: {config['time_range']}, 频率: {config['frequency']}")
    
    # 如果没有配置，提示用户
    if not pool.frequency_configs:
        print("  未找到频率配置，将使用默认值 100%")
    
    # 修改_get_current_frequency方法，增加参数传入模拟时间
    original_get_current_frequency = pool._get_current_frequency
    
    def mock_get_current_frequency(self, current_time=None):
        """模拟的获取当前频率方法，可以接收指定的时间"""
        if not self.frequency_configs:
            return 1.0  # 如果没有配置，返回100%
        
        # 使用传入的时间或当前时间
        if current_time is None:
            current_time = datetime.now().time()
        
        current_minutes = current_time.hour * 60 + current_time.minute
        
        # 遍历所有配置，检查当前时间是否在时间段内
        for config in self.frequency_configs:
            time_range = config["time_range"]
            frequency_str = config["frequency"]
            
            # 解析时间范围
            start_time_str, end_time_str = time_range.split("-")
            start_hour, start_minute = map(int, start_time_str.split(":"))
            end_hour, end_minute = map(int, end_time_str.split(":"))
            
            start_minutes = start_hour * 60 + start_minute
            end_minutes = end_hour * 60 + end_minute
            
            # 检查是否跨午夜
            crosses_midnight = end_minutes < start_minutes
            
            # 判断当前时间是否在时间段内
            in_range = False
            if crosses_midnight:
                # 如果跨午夜，则判断当前时间是否在开始时间之后或结束时间之前
                if current_minutes >= start_minutes or current_minutes < end_minutes:
                    in_range = True
            else:
                # 如果不跨午夜，则判断当前时间是否在开始时间和结束时间之间
                if start_minutes <= current_minutes < end_minutes:
                    in_range = True
            
            if in_range:
                # 解析频率百分比
                frequency = float(frequency_str.strip("%")) / 100.0
                return frequency
        
        # 如果没有匹配的时间段，返回100%
        return 1.0
    
    # 测试不同时间段的频率配置
    test_times = [
        (dt_time(10, 30), "09:00-12:00", 0.9),  # 上午10:30，应该是90%
        (dt_time(13, 45), "12:00-15:00", 0.8),  # 下午13:45，应该是80%
        (dt_time(16, 0), "15:00-17:00", 0.5),   # 下午16:00，应该是50%
        (dt_time(20, 15), "17:00-22:00", 0.7),  # 晚上20:15，应该是70%
        (dt_time(23, 30), "22:00-09:00", 1.0)   # 晚上23:30，应该是100%
    ]
    
    print("\n===== 测试不同时间段的频率配置 =====")
    for test_time, expected_range, expected_frequency in test_times:
        # 直接调用模拟函数，传入模拟时间
        frequency = mock_get_current_frequency(pool, test_time)
        
        # 打印结果
        print(f"\n当前时间: {test_time.strftime('%H:%M')}")
        print(f"预期时间段: {expected_range}")
        print(f"预期频率: {expected_frequency * 100:.0f}%")
        print(f"实际频率: {frequency * 100:.0f}%")
        print(f"结果: {'✓ 正确' if abs(frequency - expected_frequency) < 0.01 else '✗ 错误'}")
    
    print("\n===== 测试频率配置对账号间隔的影响 =====")
    # 恢复原始方法
    pool._get_current_frequency = original_get_current_frequency
    
    # 测试频率配置对账号间隔的影响
    count = 5  # 获取5个账号
    
    # 使用不同的频率测试
    test_frequencies = [1.0, 0.5, 0.8]
    
    for freq in test_frequencies:
        # 模拟一个固定的频率
        with patch.object(pool, '_get_current_frequency', return_value=freq):
            print(f"\n频率设置为: {freq * 100:.0f}%")
            accounts = pool.get_accounts_with_intervals(count)
            
            for i, item in enumerate(accounts, 1):
                account = item['account']
                interval = item['interval']
                original_interval = item['original_interval']
                next_time = item['next_available_time']
                
                print(f"\n第 {i} 个账号:")
                print(f"  ID: {account['id']}")
                print(f"  原始间隔: {original_interval} 秒")
                print(f"  调整后间隔: {interval} 秒")
                print(f"  频率影响: {interval / original_interval * 100:.0f}% (预期: {freq * 100:.0f}%)")
                print(f"  下次可用时间: {datetime.fromtimestamp(next_time).strftime('%Y-%m-%d %H:%M:%S')}")
    
    # 测试通过ID列表获取账号
    # print("\n测试通过ID列表获取账号:")
    # test_account_ids = [account['account']['id'] for account in accounts[:3]]  # 获取前3个账号的ID
    # print(f"获取账号ID: {test_account_ids}")
    # accounts = pool.get_accounts_by_ids(test_account_ids)
    # for item in accounts:
    #     account = item['account']
    #     print(f"\n账号ID {account['id']}:")
    #     print(f"  名称: {account.get('name')}")
    #     print(f"  状态: {account.get('status')}")
    #     print(f"  存活: {account.get('alive')}")
    #     print(f"  下次可用时间: {item['next_available_time_str']}")

    # # 测试定时检查功能
    # print("\n测试定时检查功能:")
    # print("启动定时检查，每60秒检查一次账号状态...")
    # print("等待65秒观察第一次定时检查结果...")
    
    # try:
    #     # 等待65秒，确保定时器触发一次
    #     time.sleep(65)
        
    #     # 获取当前账号池中的账号数量
    #     current_accounts = len(pool.account_pool)
    #     print(f"当前账号池中有 {current_accounts} 个账号")
        
    #     # 再等待65秒观察第二次检查
    #     print("\n等待65秒观察第二次定时检查结果...")
    #     time.sleep(65)
        
    #     # 再次获取账号池中的账号数量
    #     new_accounts = len(pool.account_pool)
    #     print(f"当前账号池中有 {new_accounts} 个账号")
        
    #     if new_accounts != current_accounts:
    #         print(f"账号数量发生变化: {current_accounts} -> {new_accounts}")
    #     else:
    #         print("账号数量未发生变化，所有账号状态正常")
            
    # except KeyboardInterrupt:
    #     print("\n测试被用户中断")
    # finally:
    #     # 停止定时检查
    #     pool.stop_status_check()
    #     print("\n已停止定时检查")

if __name__ == "__main__":
    main()
